package xyz.xxin.xat.utils;

import android.os.AsyncTask;
import android.os.Environment;
import android.text.TextUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class DownloadUtils extends AsyncTask<String, Integer, Integer> {
    private static final int TYPE_SUCCESS = 0;  // 下载成功
    private static final int TYPE_FAILED = 1;   // 下载失败
    private static final int TYPE_PAUSED = 2;   // 下载暂停
    private static final int TYPE_CANCELED = 3; // 下载取消

    private boolean isPaused = false;           // 是否暂停
    private boolean isCanceled = false;         // 是否取消

    private int lastProgress;                   // 记录进度值

    private File downloadCacheFile;             // 下载到本地的缓存文件
    private File downloadFile;                  // 下载到本地的文件


    private final DownloadListener downloadListener;    // 下载监听

    public DownloadUtils(DownloadListener downloadListener) {
        this.downloadListener = downloadListener;
    }

    /**
     * 通过execute执行时，需要在传入的数组中添加三个参数，且顺序固定
     * 1. 文件下载链接
     * 2. 存放下载文件的目录的路径
     * 3. 文件名
     */
    @Override
    protected Integer doInBackground(String... strings) {
        // 下载链接
        String downloadUrl = strings[0];
        // 文件所在目录的路径
        String folderPath = strings[1];
        // 文件名
        String fileName = strings[2];

        // 如果下载链接为空，直接return出去
        if (downloadUrl == null || TextUtils.isEmpty(downloadUrl))
            return null;
        // 如果所在目录的路径不正确
        if (folderPath == null || TextUtils.isEmpty(folderPath))
            folderPath = Environment.getExternalStorageDirectory().getAbsolutePath();
        // 如果文件名不正确
        if (fileName == null || TextUtils.isEmpty(fileName))
            fileName = getDownloadFileName(downloadUrl);

        // 下载到本地的文件路径
        String downloadFilePath = folderPath + "/" + fileName;
        // 下载到本地的文件
        downloadFile = new File(downloadFilePath);

        // 下载到本地的缓存文件路径
        String downloadCacheFilePath = folderPath + "/" + fileName + "_cache";
        // 下载到本地的缓存文件
        downloadCacheFile = new File(downloadCacheFilePath);

        // 已经下载的缓存文件大小
        long downloadCacheFileLength = 0;
        // 获取已经下载的缓存文件大小
        if (downloadCacheFile.exists() && downloadCacheFile.isFile()) {
            downloadCacheFileLength = downloadCacheFile.length();
        }

        // 要下载的文件的大小
        long downloadFileLength = getDownloadFileLength(downloadUrl);
        if (downloadFileLength == 0) {
            return TYPE_FAILED; // 下载失败
        } else if (downloadFileLength == downloadCacheFileLength) {
            return TYPE_SUCCESS; // 下载成功
        }

        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .addHeader("RANGE", "bytes=" + downloadCacheFileLength + "-") // 指定下载区间
                .url(downloadUrl)
                .build();

        try {
            Response execute = okHttpClient.newCall(request).execute();
            ResponseBody body = execute.body();
            if (execute.isSuccessful() && body != null) {
                InputStream inputStream = body.byteStream();
                RandomAccessFile randomAccessFile = new RandomAccessFile(downloadCacheFile, "rw");
                randomAccessFile.seek(downloadCacheFileLength); // 跳过已经下载的字节
                byte[] bytes = new byte[1024];
                int total = 0;
                int len;
                while ((len = inputStream.read(bytes)) != -1) {
                    if (isCanceled) {
                        return TYPE_CANCELED;
                    } else if (isPaused) {
                        return TYPE_PAUSED;
                    } else {
                        total += len;
                        randomAccessFile.write(bytes, 0, len);
                        int progressValue = (int) ((total + downloadCacheFileLength) * 100 / downloadFileLength);
                        publishProgress(progressValue);
                    }
                }
                body.close();
                return TYPE_SUCCESS;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return TYPE_FAILED;
    }

    /**
     * 获取下载的文件的大小
     * @param url 下载链接
     * @return 文件大小
     */
    private long getDownloadFileLength(String url){
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        long length = 0;
        try {
            Response execute = okHttpClient.newCall(request).execute();
            ResponseBody body = execute.body();
            if (execute.isSuccessful() && body != null){
                length = body.contentLength();
                body.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return length;
    }

    /**
     * 获取下载链接中的文件名
     * @param url 下载链接
     * @return 文件名
     */
    private String getDownloadFileName(String url){
        int lastIndexOf = url.lastIndexOf("/");
        return url.substring(lastIndexOf);
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        int progress = values[0];
        if (progress > lastProgress) {
            downloadListener.onProgress(progress);
            lastProgress = progress;
        }
    }

    @Override
    protected void onPostExecute(Integer integer) {
        super.onPostExecute(integer);
        switch (integer) {
            case TYPE_SUCCESS:
                removeFile();
                downloadListener.onSuccess(downloadFile);
                break;
            case TYPE_FAILED:
                downloadListener.onFailed();
                break;
            case TYPE_PAUSED:
                downloadListener.onPaused();
                break;
            case TYPE_CANCELED:
                deleteCache();
                downloadListener.onCanceled();
                break;
            default:
                break;
        }
    }

    /**
     * 删除下载缓存
     */
    private void deleteCache() {
        downloadCacheFile.delete();
    }

    /**
     * 将缓存文件重命名为目标文件
     */
    private void removeFile() {
        if (downloadFile.exists() && downloadFile.isFile()) {
            downloadFile.delete();
        }
        downloadCacheFile.renameTo(downloadFile);
    }

    /**
     * 调用该方法暂停下载
     */
    public void pauseDownload() {
        this.isPaused = true;
    }

    /**
     * 调用该方法取消下载
     */
    public void cancelDownload() {
        this.isCanceled = true;
    }

    public interface DownloadListener {
        // 下载进度
        void onProgress(int progress);

        // 下载成功
        void onSuccess(File downloadCacheFile);

        // 下载失败
        void onFailed();

        // 下载暂停
        void onPaused();

        // 下载取消
        void onCanceled();
    }
}
